#include <cmath>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <ios>

#define lambda -1000000
#define epsilon 0.000000000001

class Point {
public:
	double __u;
	double __t;
	Point(){};
	~Point(){};
	Point(const double _u, const double _t) {
		__u = _u;
		__t = _t;
	}
	Point& operator=(const Point &_p) {
		if(this != &_p) {
			this -> __u = _p.__u;
			this -> __t = _p.__t;
		}
		return *this;
	};
};

class function {
public:
	double operator()(const double _t) {
		double r = 0;
		r = -lambda*cos(_t) - sin(_t);
		return r;
	};
};

/*class dfunction {
public:
	double operator()(const Point _p) {
		double r = 0;
		function f;
		r = lambda*lambda*(_p.__u - cos(_p.__t)) - lambda*cos(_p.__t);
		return r;
	}
};*/

void BackwardEuler(Point& _x, double _k) {
	function f;
	_x.__u = (_x.__u + _k*f(_x.__t + _k))/(1.0 - lambda*_k);
	_x.__t = _x.__t + _k;
};

void Trapezoidal(Point& _x, double _k) {
	function f;
	_x.__u = (_x.__u + 0.5*_k*lambda*_x.__u + 0.5*_k*f(_x.__t) + 0.5*_k*f(_x.__t + _k))/(1.0 - 0.5*_k*lambda);
	_x.__t = _x.__t + _k;
}


int main(int argc, char *argv[])
{
	std::ofstream out_E("BackwardEuler_error.txt");
	std::ofstream out_T("Traprezoidal_error.txt");
	Point x;
	Point y;
	double etalist[2] = {1.0, 1.5}; 
	double klist[3] = {0.2, 0.1, 0.05};
	double step[3] = {15, 30, 60};
	double e_x, e_y;
	double k;
	for(int l = 0; l != 2; l++) {
		double r_s = exp(lambda*3.0)*(etalist[l] - 1.0) + cos(3.0);
		for(int i = 0; i != 3; i++) {
			x.__u = etalist[l];
			x.__t = 0;
			y.__u = etalist[l];
			y.__t = 0;
			k = klist[i];
			for(int j = 0; j != step[i]; j++) {
				BackwardEuler(x, k);
				Trapezoidal(y, k);	
			}
			e_x = r_s - x.__u;
			e_y = r_s - y.__u;
			e_x = fabs(e_x);
			e_y = fabs(e_y);
			out_E << etalist[l] << '\t' << k << '\t' << std::scientific << e_x << std::endl;
			out_E << std::fixed;
			out_E.unsetf(std::ios::fixed);
			out_T << etalist[l] << '\t' << k << '\t' << std::scientific << e_y << std::endl;
			out_T << std::fixed;
			out_T.unsetf(std::ios::fixed);
		}
	}
	out_E.close();
}

